package com.unionServer.models;

import com.unionServer.common.*;
import io.netty.util.internal.StringUtil;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Element;
import org.springframework.util.StringUtils;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Iterator;

/**
 * @description:
 * @author: wangxinal
 * @time: 2022/1/18 9:41
 */
@Slf4j
public class MessageBody {
    @Getter
    @Setter
    HashMap<String, Object> messageBodyMap = new HashMap<String, Object> ();

    BinaryIntConvertor binaryIntConvertor = new BinaryIntConvertor() ;

    ATMPINConverter atmpinConverter = new ATMPINConverter() ;

    LBCDHexConverter lbcdHexConverter = new LBCDHexConverter() ;

    ICCDataConvertor iccDataConvertor = new ICCDataConvertor();

    public MessageBody(byte[] bodyBytes, String bitMapStr, Element bodyElm,String messageTypeId) throws Exception {

        messageBodyMap.put("MSG_TYPE_ID", messageTypeId);

        BufferedInputStream in = null;
        in = new BufferedInputStream(new ByteArrayInputStream(bodyBytes));
        Iterator itr = bodyElm.elementIterator();

        int i = 2;
        for (char bodyFlag: bitMapStr.substring(1).toCharArray()) {
            Element curNode = (Element)itr.next();
            String type = curNode.attributeValue("type");
            //if (i == 2){
            if (bodyFlag == '1'){
                boolean isLLVAR = "LLVAR".equalsIgnoreCase(type);
                boolean isLLLVAR = "LLLVAR".equalsIgnoreCase(type);
                int length = -1 ;
                if(isLLVAR){
                    byte[] lenBytes = new byte[2];
                    in.read(lenBytes) ;
                    length = decodeLength(lenBytes) ;
                }else if(isLLLVAR){
                    byte[] lenBytes = new byte[3];
                    in.read(lenBytes) ;
                    length = decodeLength(lenBytes) ;
                }else{
                    length = curNode.attributeValue("compressLength") == null ? Integer.parseInt(curNode.attributeValue("length")) : Integer.parseInt(curNode.attributeValue("compressLength"));
                }
                byte[] temp = new byte[length];
                in.read(temp) ;
                String charset = "ASCII" ;
                if (curNode.attributeValue("encoding") != null)
                {
                    charset = curNode.attributeValue("encoding") ;
                }

                boolean lazyParse = Boolean.parseBoolean(curNode.attributeValue("lazyParse")== null ? "false" :curNode.attributeValue("lazyParse"));
                if(isSwitch(curNode) && !lazyParse){
                    dealSwitch(curNode, in, i, messageBodyMap, false);
                }
                if (curNode.attributeValue("mode") != null && curNode.attributeValue("mode").equals("ATMPIN") ){
                    String tempStr = new String(atmpinConverter.getFromBcd(temp),StandardCharsets.US_ASCII ).trim();
                    messageBodyMap.put(curNode.getQName().getName(), tempStr);
                }else if (curNode.attributeValue("mode") != null && curNode.attributeValue("mode").equals("LBCD_HEX") ){
                    String tempStr = new String(lbcdHexConverter.getFromBcd(temp,Integer.parseInt(curNode.attributeValue("length")) ,"ASCII"),StandardCharsets.US_ASCII ).trim();
                    messageBodyMap.put(curNode.getQName().getName(), tempStr);
                }else {
                    messageBodyMap.put(curNode.getQName().getName(), new String(temp, charset ));
                }
                if(curNode.attributeValue("submode") != null && curNode.attributeValue("submode").equals("ICC")){
                    iccDataConvertor.getFromBcd(messageBodyMap.get (curNode.getQName().getName()).toString(),curNode.getQName().getName(),messageBodyMap );
                }else if(curNode.attributeValue("submode") != null ){
                    String strTemp = messageBodyMap.get(curNode.getQName().getName()).toString() ;
                    if(curNode.attributeValue("submode").equals("lengthSplit")){
                        FieldUnpack.StringLengthUnPack(strTemp,curNode.getQName().getName(),messageBodyMap,curNode.element("blend"));
                    }else if(curNode.attributeValue("submode").equals("ATMPINSplit")){
                        FieldUnpack.AtmpinUnPackTLVTag(strTemp,curNode.getQName().getName(),messageBodyMap,curNode.element("blend"));
                    }else if(curNode.attributeValue("submode").equals("StringTagSplit")){
                        FieldUnpack.AtmpinUnPackTLVTag(strTemp,curNode.getQName().getName(),messageBodyMap,curNode.element("blend"));
                    }
                }

                log.info("第"+ i + "域值为："+ (String) messageBodyMap.get (curNode.getQName().getName()));

            }
            i++ ;
        }
    }

    private void dealSwitch(Element node, BufferedInputStream in, int fieldIndex, HashMap<String, Object> map, boolean callByLazyProc) throws Exception {

        log.info(String.format("域[%d]配置了条件拆包,字段名[%s]", fieldIndex, node.attributeValue("switchfield")));

        String[] pathArray = node.attributeValue("switchfield").split("\\|");
        StringBuffer sb = new StringBuffer();
        StringBuffer sb2 = new StringBuffer();
        String[] arr = pathArray;
        int len$ = pathArray.length;

        String caseNodeName;
        for(int i = 0; i < len$; ++i) {
            caseNodeName = arr[i];
            if (caseNodeName == null) {
                throw new Exception("解析分支节点[" + node.getName() + "]时,条件表达式的路径不可用");
            }

            if (!map.containsKey(caseNodeName) && !hasDefaultChild(node)) {
                throw new Exception("已拆包数据中缺少条件表达式对应的值, 且未配置default拆包节点,表达式：" + caseNodeName);
            }

            log.info("获取条件值：" + caseNodeName + "=" + map.get(caseNodeName));


            if (map.get(caseNodeName) == null) {
                sb.append("&nbsp;");
                sb2.append("|");
            } else {
                sb.append(map.get(caseNodeName)).append("&nbsp;");
                sb2.append(map.get(caseNodeName)).append("|");
            }
        }

        String factValue = sb.toString();
        log.info("条件运行结果:" + sb2.toString());

    }
    private boolean hasDefaultChild(Element node) {
        return node != null && node.element("default") != null;
    }

    public String byteArr2HexStr(byte[] arrB)
            throws IOException
    {
        int iLen = arrB.length;

        StringBuffer sb = new StringBuffer(iLen * 2);

        for (int i = 0; i < iLen; ++i)
        {
            int intTmp = arrB[i];

            while (intTmp < 0)
            {
                intTmp += 256;
            }

            if (intTmp < 16)
            {
                sb.append("0");
            }

            sb.append(Integer.toString(intTmp, 16));
        }

        return sb.toString();
    }
    public int decodeLength(byte[] lenBytes) {
        log.debug("解码前长度段数据(toString):" + new String(lenBytes));
        int i = Integer.parseInt(new String(lenBytes));
        log.debug("解码后长度(10进制):" + i);
        return i;
    }
    private boolean isSwitch(Element element) {
        return element != null && element.attributeValue("switchfield") != null && element.attributeValue("switchmode") != null;
    }



    @Override
    public String toString() {
        return "MessageBody{" +
                "messageBodyMap=" + messageBodyMap +
                '}';
    }
}
